#pragma once
#include "mutex.hpp"
#include "cond.hpp"
#include <queue>
#include <iostream>

namespace myblockqueue
{
    using namespace LockModule;
    using namespace CondModule;
    const static int defaulcap = 10;
    template <typename T>
    class BlockQueue
    {
    private:
        bool isfull()
        {
            return _queue.size() == _cap;
        }
        bool isempty()
        {
            return _queue.empty();
        }

    public:
        BlockQueue(int cap = defaulcap) : _cap(cap), _consume_wait(0), _produce_wait(0)
        {
        }

        void equeue(const T &in) // 生产
        {
            LockGuard  lg(_mutex);
            while (isfull())
            {
                std::cout << "queue is full, producer is waiting..." << std::endl;
                _produce_wait++;
                _condproduce.Wait(_mutex);
                _produce_wait--;
                std::cout << "producer is waiting end..." << std::endl;
            }
                _queue.push(in);
            
            if(_consume_wait > 0)
            {
                _condconsume.Notify();
            }
        }
        void dequeue(T *out) // 消费
        {
            LockGuard  lg(_mutex);
            while (isempty())
            {
                std::cout << "queue is empty, consumer is waiting..." << std::endl;
                _consume_wait++;
                _condconsume.Wait(_mutex);
                _consume_wait--;
                std::cout << "consumer is waiting end..." << std::endl;
            }
            if(_produce_wait > 0)
            {

                _condproduce.Notify();
            }
            *out = _queue.front();
            _queue.pop();
        }
        ~BlockQueue()
        {
        }

    private:
        std::queue<T> _queue;
        int _cap;
        Mutex _mutex;
        Cond _condconsume;
        Cond _condproduce;

        // 用于统计阻塞的线程数
        int _consume_wait;
        int _produce_wait;
    };
} // namespace myblockqueue
